package com.example.t1_spring_security_demo.config;

import com.example.t1_spring_security_demo.handle.MyAccessDeniedHandler;
import com.example.t1_spring_security_demo.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * SpringSecurity配置类
 *
 * @Author fachang.mao
 * @Date 2021/11/21 9:30
 * @Version 1.0
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private DataSource datasource;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //表单提交
        http.formLogin()
                .usernameParameter("username123")
                .passwordParameter("password123")
                //发现/login时认为是登录，必须和表单提交的地址一样，去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/showLogin")
                //登录成功后跳转页面，必须是post请求
                .successForwardUrl("/toMain")
//                //登录成功后的处理器，不能和successForwardUrl共存
//                .successHandler(new MyAuthenticationSuccessHandler("/main.html"))
                //登录失败后跳转页面，必须是post请求
                .failureForwardUrl("/toError");
//                //登录失败后的处理器，不能和failureForwardUrl共存
//                .failureHandler(new MyAuthenticationFailureHandler("/error.html"));

        //授权认证
        http.authorizeRequests()
                //error.html不需要被认证
//                .antMatchers("/error.html").permitAll()
                .antMatchers("/error.html").access("permitAll()")
                //login.html不需要被认证
//                .antMatchers("/login.html").permitAll()
                .antMatchers("/showLogin").access("permitAll()")
                .antMatchers("/js/**","/css/**","/images/**").permitAll()
                //.antMatchers("/**/*.png").permitAll()
                //正则表达式匹配
                //.regexMatchers(".+[.]png").permitAll()
                //.regexMatchers(HttpMethod.POST,"/demo").permitAll()
                //mvc匹配servletPath为特有方法，其他2种匹配方式没有
                //.mvcMatchers("/demo").servletPath("/example").permitAll()
                //和mvc匹配等效
                //.antMatchers("/example/demo").permitAll()
                //权限判断
                //.antMatchers("/main1.html").hasAuthority("admin")
                //.antMatchers("/main1.html").hasAnyAuthority("admin", "admiN")
                //角色判断
                //.antMatchers("/main1.html").hasRole("abc")
                //.antMatchers("/main1.html").access("hasRole('abc')")
                //.antMatchers("/main1.html").hasAnyRole("abc","abC")
                //.antMatchers("/main1.html").hasIpAddress("127.0.0.1")
                //所有请求都必须被认证，必须登录之后被访问
                .anyRequest().authenticated();
                //.anyRequest().access("@myServiceImpl.hasPermission(request, authentication)");

        //关闭scrf防护
//        http.csrf().disable();

        //异常处理
        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler);

        //记住我
        http.rememberMe()
                //失效时间，单位秒 默认两周(TWO_WEEKS_S = 1209600)
                .tokenValiditySeconds(60)
                //.rememberMeParameter()
                //自定义登录逻辑
                .userDetailsService(userDetailsService)
                //持久层登录对象
                .tokenRepository(persistentTokenRepository);

        //退出登录
        http.logout()
                //.addLogoutHandler()
                .logoutUrl("/logout")
                //退出登录跳转页面
                .logoutSuccessUrl("/login.html");
    }

    @Bean
    public PasswordEncoder getPw(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(datasource);
        //自动建表，第一次启动是需要，第二次启动需要注释掉
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}
